﻿using System;
using System.Collections.Generic;
using System.Text;
using Resolve.Contracts;
using Resolve.FlagInfo;

namespace Resolve.Core
{
    public sealed class CodeGenerater : CodeGeneraterBase
    {
        /// <summary>
        /// 组合代码
        /// </summary>
        /// <returns></returns>
        public override CodeInfo CombineCode()
        {
            if (FlagCodeInFile == null || FlagCodeInFile.LsCode == null || FlagCodeInFile.LsCode.Count == 0)
            {
                return null;
            }
            StringBuilder sbBodyCode = new StringBuilder();
            List<string> lsUsing = new List<string>();
            List<FlagCode> lsCode = FlagCodeInFile.LsCode;
            for (int i = 0; i < lsCode.Count; i++)
            {
                if (i == 0)
                {
                    //sbBodyCode.Append("namespace " + ResolveConfig.CompileNameSpace + "\r\n{\r\n");
                    sbBodyCode.Append("\tpublic class " + FlagCodeInFile.ClassName.ToLower() + ":ViewPageBase\r\n\t{\r\n");
                    sbBodyCode.Append("\t\tpublic " + FlagCodeInFile.ClassName.ToLower() + "(IDictionary<string, object> viewData, IDictionary<string, object> model):base(viewData,model)\r\n");
                    sbBodyCode.Append("\t\t{\r\n");
                    sbBodyCode.Append("\t\t\tSetLayout(); LayoutProc();\r\n");
                    sbBodyCode.Append("\t\t}\r\n");
                }
                string sTemp = lsCode[i].Code;
                switch (lsCode[i].FlagStyle)
                {
                    case FlagStyle.Using:
                        GenerateUsing(sTemp, ref lsUsing);
                        break;
                    case FlagStyle.Statement:
                        sTemp = GenerateStatement(sTemp);
                        break;
                    case FlagStyle.Property:
                        sTemp = GenerateProperty(i, sTemp);
                        break;
                    case FlagStyle.Layout:
                        sTemp = GenerateLayout(sTemp);
                        break;
                    case FlagStyle.Func:
                        sTemp = GenerateFunc(i, sTemp);
                        break;
                    case FlagStyle.Body:
                        sTemp = GenerateBody(i, sTemp, null);
                        break;
                    case FlagStyle.PlaceContent:
                        sTemp = GeneratePlaceContent(i, sTemp);
                        break;
                    case FlagStyle.FlagEscape:
                    case FlagStyle.Comment:
                    case FlagStyle.PlaceHolder:
                        sTemp = string.Empty;
                        break;
                }
                if (lsCode[i].FlagStyle != FlagStyle.Using)
                {
                    sbBodyCode.Append(sTemp + "\r\n");
                }
            }
            sbBodyCode.Append("\t}\r\n");
            //sbBodyCode.Append("}\r\n");
            //AmendUsing(ref lsUsing);
            CodeInfo codeInfo = new CodeInfo { BodyCode = sbBodyCode.ToString(), LsUsing = lsUsing };
            return codeInfo;
        }

        ///// <summary>
        ///// 更正Using
        ///// </summary>
        ///// <returns></returns>
        //private static void AmendUsing(ref List<string> lsUsing)
        //{
        //    if (lsUsing.Count == 0)
        //    {
        //        lsUsing.Add("using System.Globalization;\r\n");
        //        lsUsing.Add("using System.Collections.Generic;\r\n");
        //        lsUsing.Add("using System.Text;\r\n");
        //        lsUsing.Add("using Resolve.Web;\r\n");
        //    }
        //    else
        //    {
        //        if (!lsUsing.Contains("using System.Globalization;\r\n"))
        //        {
        //            lsUsing.Add("using System.Globalization;\r\n");
        //        }
        //        if (!lsUsing.Contains("using System.Collections.Generic;\r\n"))
        //        {
        //            lsUsing.Add("using System.Collections.Generic;\r\n");
        //        }
        //        if (!lsUsing.Contains("using System.Text;\r\n"))
        //        {
        //            lsUsing.Add("using System.Text;\r\n");
        //        }
        //        if (!lsUsing.Contains("using Resolve.Web;\r\n"))
        //        {
        //            lsUsing.Add("using Resolve.Web;\r\n");
        //        }
        //    }
        //}

        /// <summary>
        /// 生成Using代码段
        /// </summary>
        /// <param name="usingCode"></param>
        /// <param name="lsUsing"></param>
        /// <returns></returns>
        private static void GenerateUsing(string usingCode, ref List<string> lsUsing)
        {
            usingCode = usingCode.Trim();
            if (string.IsNullOrEmpty(usingCode))
            {
                return;
            }
            string sTemp = usingCode;
            sTemp = sTemp.Remove(0, 9);//去掉@using{回车
            sTemp = sTemp.Remove(sTemp.Length - 3);//去掉}回车
            string[] array = sTemp.Split(';');
            foreach (string s in array)
            {
                if (string.IsNullOrEmpty(s) || lsUsing.Contains(s))
                {
                    continue;
                }
                lsUsing.Add("using " + s.Trim() + ";\r\n");
            }
        }

        /// <summary>
        /// 生成声明代码段
        /// </summary>
        /// <param name="statementCode"></param>
        /// <returns></returns>
        private static string GenerateStatement(string statementCode)
        {
            statementCode = statementCode.Trim();
            if (string.IsNullOrEmpty(statementCode))
            {
                return string.Empty;
            }
            statementCode = statementCode.Remove(0, 4);//去掉@{回车
            statementCode = statementCode.Remove(statementCode.Length - 3);//去掉@}回车
            string[] array = statementCode.Split(';');
            statementCode = string.Empty;
            foreach (string s in array)
            {
                if (string.IsNullOrEmpty(s))
                {
                    continue;
                }
                string temp = s.Trim();
                int iIndex = temp.IndexOf('=');
                if (iIndex == -1)
                {
                    throw new Exception(s);
                }
                statementCode += "\t\tpublic " + temp.Substring(0, iIndex) + "\r\n\t\t{\r\n";
                statementCode += "\t\t\tget {return " + temp.Substring(iIndex + 1) + ";}\r\n";
                statementCode += "\t\t\tset {}\r\n";
                statementCode += "\t\t}\r\n";
            }
            return statementCode;
        }

        /// <summary>
        /// 生成模板引用
        /// </summary>
        /// <param name="layout"></param>
        /// <returns></returns>
        private static string GenerateLayout(string layout)
        {
            layout = layout.Remove(0, 1);
            return "\t\tpublic override void  SetLayout()\r\n\t\t{\r\n\t\t\t" + layout + ";\r\n\t\t}";
        }

        /// <summary>
        /// 生成属性代码段
        /// </summary>
        /// <param name="index"></param>
        /// <param name="propertyCode"></param>
        /// <returns></returns>
        private static string GenerateProperty(int index, string propertyCode)
        {
            if (string.IsNullOrEmpty(propertyCode))
            {
                return string.Empty;
            }
            string sTemp = propertyCode.Trim();
            sTemp = sTemp.Remove(0, 1);//去掉标志
            if (sTemp.EndsWith("]"))
            {
                sTemp = "\t\tpublic string " + ResolveConfig.PropertyCodeName + index +
                        "()\r\n\t\t{\r\n\t\t\treturn " + sTemp + ".ToString();\r\n\t\t}";
            }
            else
            {
                sTemp = "\t\tpublic string " + ResolveConfig.PropertyCodeName + index +
                        "()\r\n\t\t{\r\n\t\t\treturn " + sTemp + ".ToString(CultureInfo.InvariantCulture);\r\n\t\t}";
            }
            return sTemp;
        }

        /// <summary>
        /// 生成方法代码段
        /// </summary>
        /// <param name="index"></param>
        /// <param name="bodyCode"></param>
        /// <returns></returns>
        private static string GenerateFunc(int index, string bodyCode)
        {
            if (string.IsNullOrEmpty(bodyCode))
            {
                return string.Empty;
            }
            string sTemp = bodyCode.Trim();
            sTemp = sTemp.Remove(0, 1);//去掉标志
            sTemp = "\t\tpublic string " + ResolveConfig.FuncCodeName + index + "()\r\n\t\t{\r\n\t\t\treturn " + sTemp + ";\r\n\t\t}";
            return sTemp;
        }

        ///// <summary>
        ///// 占位符
        ///// </summary>
        ///// <param name="index"></param>
        ///// <param name="contentCode"></param>
        ///// <returns></returns>
        //private static string GeneratePlaceHolder(int index, string contentCode)
        //{
        //    if (string.IsNullOrEmpty(contentCode))
        //    {
        //        return string.Empty;
        //    }
        //    string sTemp = contentCode.Trim();
        //    sTemp = sTemp.Remove(0, 1);//去掉标志
        //    sTemp = sTemp.Replace("\"", "_");
        //    sTemp = sTemp.Replace("(", "");
        //    sTemp = sTemp.Replace(")", "");
        //    sTemp = "\t\tpublic string " + ResolveConfig.FuncCodeName + index + "()\r\n\t\t{\r\n\t\t\treturn \"<!--" + sTemp + "-->\";\r\n\t\t}";
        //    return sTemp;
        //}

        /// <summary>
        /// 占位符内容替换代码
        /// </summary>
        /// <param name="index"></param>
        /// <param name="contentCode"></param>
        /// <returns></returns>
        private static string GeneratePlaceContent(int index, string contentCode)
        {
            int iIndex = contentCode.IndexOf('{');
            if (iIndex <= -1) return GenerateBody(index, contentCode, "");
            string name = contentCode.Substring(0, iIndex);
            contentCode = contentCode.Remove(0, iIndex + 1);
            iIndex = contentCode.LastIndexOf('}');
            contentCode = contentCode.Remove(iIndex);
            iIndex = name.IndexOf('"');
            name = name.Substring(iIndex + 1);
            iIndex = name.IndexOf('"');
            name = name.Substring(0, iIndex);
            return GenerateBody(index, contentCode, ResolveConfig.PlaceContentName + name);
        }

        /// <summary>
        /// 生成语句代码段
        /// </summary>
        /// <param name="index"></param>
        /// <param name="bodyCode"></param>
        /// <param name="funcName"></param>
        /// <returns></returns>
        private static string GenerateBody(int index, string bodyCode, string funcName)
        {
            if (string.IsNullOrEmpty(bodyCode))
            {
                return string.Empty;
            }
            string sTemp = bodyCode;
            StringBuilder sbCode = new StringBuilder();
            if (string.IsNullOrEmpty(funcName))
            {
                funcName = ResolveConfig.BodyCodeName + index;
            }
            sbCode.Append("\t\tpublic string " + funcName + "()\r\n\t\t{\r\n");
            sbCode.Append("\t\t\tStringBuilder htmlCode=new StringBuilder();");
            char[] codeArray = sTemp.ToCharArray();
            sTemp = string.Empty;
            string sTab = "\t\t\t";
            int last1 = -1;//上一个字符
            bool bFindFlagOnline = false;//是否找到标志
            int iSmallLevel = 0;//小括号层次数
            int iBigLevel = 0;//大括号层次数
            bool bIntoDouble = false;//是否进入双引号
            foreach (char current in codeArray)
            {
                //找到标志
                if (current == ResolveConfig.Flag && !bFindFlagOnline)
                {
                    bFindFlagOnline = true;
                    last1 = current;
                    if (!string.IsNullOrEmpty(sTemp))
                    {
                        sbCode.Append("\r\n" + sTab + "htmlCode.Append(\"" + sTemp + "\");");
                    }
                    sTemp = string.Empty;
                    continue;
                }
                if (current == ResolveConfig.Flag && last1 == ResolveConfig.Flag && bFindFlagOnline) //找到@@，标志无效
                {
                    bFindFlagOnline = false;
                }
                if (bFindFlagOnline)
                {
                    if (current == 34 && !bIntoDouble)//("
                    {
                        bIntoDouble = true;
                        sTemp += current;
                    }
                    else if (current == 34 && last1 != 92 && bIntoDouble)//\")
                    {
                        bIntoDouble = false;
                        sTemp += current;
                    }
                    else if (current == 40 && !bIntoDouble)//(
                    {
                        iSmallLevel++;
                        sTemp += current;
                    }
                    else if (current == 41 && !bIntoDouble)//)
                    {
                        iSmallLevel--;
                        sTemp += current;
                    }
                    else if (last1 != ResolveConfig.Flag && current == 123 && !bIntoDouble)//{
                    {
                        iBigLevel++;
                        sTemp += current;
                        sbCode.Append("\r\n" + sTab + sTemp);
                        sTab += "\t";
                        sTemp = string.Empty;
                        bFindFlagOnline = false;
                    }
                    else if (last1 != ResolveConfig.Flag && current == 125 && !bIntoDouble)//}
                    {
                        iBigLevel--;
                        sTemp += current;
                        sbCode.Append("\r\n" + sTab + sTemp);
                        sTab = sTab.Remove(sTab.Length - 2);
                        sTemp = string.Empty;
                        bFindFlagOnline = false;
                        if (iBigLevel == 0)
                        {
                            break;
                        }
                    }
                    else if (current == 32 && !bIntoDouble && iSmallLevel == 0)//空格
                    {
                        if (ResolveConfig.IsKeyWord(sTemp))
                        {
                            sbCode.Append("\r\n" + sTab + "htmlCode.Append(\"" + sTemp + "\\r\\n\");");
                        }
                        else
                        {
                            sbCode.Append("\r\n" + sTab + "htmlCode.Append(" + sTemp + ");");
                        }
                        sTemp = string.Empty;
                        bFindFlagOnline = false;
                    }
                    else if (last1 == 13 && current == 10)//回车
                    {
                        if (ResolveConfig.IsKeyWord(sTemp))
                        {
                            sbCode.Append("\r\n" + sTab + "htmlCode.Append(\"" + sTemp + "\\r\\n\");");
                        }
                        else
                        {
                            sbCode.Append("\r\n" + sTab + "htmlCode.Append(" + sTemp + "+\"\\r\\n\");");
                        }
                        sTemp = string.Empty;
                        bFindFlagOnline = false;
                    }
                    else
                    {
                        if (current != 13)
                        {
                            sTemp += current;
                        }
                    }
                }
                else
                {
                    if (last1 == 13 && current == 10) //回车
                    {
                        if (!string.IsNullOrEmpty(sTemp))
                        {
                            string sTemp2 = sTemp.Trim();
                            if (ResolveConfig.IsKeyWord(sTemp2))
                            {
                                sbCode.Append("\r\n" + sTab + sTemp2);
                                if (sTemp2.EndsWith("{"))
                                {
                                    iBigLevel++;
                                }
                                if (sTemp2.EndsWith("}"))
                                {
                                    iBigLevel--;
                                }
                            }
                            else
                            {
                                sbCode.Append("\r\n" + sTab + "htmlCode.Append(\"" + sTemp + "\\r\\n\");");
                            }

                        }
                        sTemp = string.Empty;
                    }
                    else
                    {
                        if (current != 13)
                        {
                            if (current == 34 || current == 92)//转义符
                            {
                                sTemp += "\\";
                            }

                            sTemp += current;
                        }
                    }
                }
                last1 = current;
            }
            sbCode.Append("\r\n\t\t\treturn htmlCode.ToString();\r\n\t\t}");
            return sbCode.ToString();
        }
    }
}